//
// Created by Administrator on 2024/7/15.
//

#pragma once
#include <iostream>
#include <string>
#include <stdexcept>


namespace reflect_enum{

    namespace details{

        template<typename T,T n>
        const char* get_enum_name_static(){
#if defined(_MSC_VER)
            return __FUNCSIG__;
#else
//            printf("%s",__PRETTY_FUNCTION__);
            return __PRETTY_FUNCTION__;
#endif
        }

        // ʹ�����type �����±������׳�����
        template<bool Cond>
        struct my_enable_if{

        };

        // ����ģ��,ʹ�ø÷�ʽ������type ������Ϊvoid ����
        template<>
        struct my_enable_if<true>{
            typedef void type;
        };


        // beg == end ʱ,�׳�����
        template<int Beg,int End,class F>
        typename my_enable_if<Beg == End>::type static_for(F const &func){

        }

        template<int Begin,int End,class F>
        typename my_enable_if<Begin != End>::type static_for(F const &func){
            func.template call<Begin>();
            static_for<Begin + 1,End>(func);

        }

        template <class T>
        struct get_enum_name_functor{
            T n;
            std::string &s;

            get_enum_name_functor(T n,std::string &s):n(n),s(s){

            }

            template<int I>
            void call() const {
                if ((int)n == I) s = details::get_enum_name_static<T,(T)I>();
            }
        };

    }


    template <class T, T Beg, T End>
    std::string get_enum_name(T n) {
        std::string s;

        details::static_for<(int)Beg,(int)End>(details::get_enum_name_functor<T>(n,s));
        if (s.empty()){
            return "";
        }
#if defined(_MSC_VER)

        size_t pos = s.find(',');
        pos += 1;
        size_t pos2 = s.find('>', pos);
#else
        size_t pos = s.find("; T n = ");
        s = s.substr(pos,s.length()-pos);
        pos = s.find(")") +1;
//        pos += 4;
        size_t pos2 = s.find_first_of("]", pos);
#endif
        s = s.substr(pos,pos2-pos);
        size_t pos3 = s.find("::");
        if (pos3 != s.npos)
            s = s.substr(pos3 + 2);
        return s;
    }

    template <class T>
    std::string get_enum_name(T n) {
        return get_enum_name<T,T(0),T(256)>(n);
    }

    template <class T, int Beg, int End>
    T enum_from_name(std::string const &s) {

        for (int i = Beg; i < End; ++i) {
            if (s == get_enum_name<T>(T(i))){
                return (T)i;
            }
        }
        std::cout << "now enum error in "<<__FILE__<<":"<<__LINE__ << s << std::endl;
        return T(0);
    }

    template <class T>
    T enum_from_name(std::string const &s) {
        return enum_from_name<T,0,256>(s);
    }

}

template<class T, std::enable_if_t<std::is_enum_v<T>, int>  = 0>
std::ostream& operator<<(std::ostream& os, T emum_value) {
    os << reflect_enum::get_enum_name(emum_value);
    return os;
}